/**
 * Created by jinxs on 14-8-11.
 */
(function ($) {
    /**
     * 缓存名称
     * @type {String}
     * @private
     */
    var _cacheName = 'uiDate';
    /**
     * @class 日期输入框
     * @requires {@link My97DatePicker}
     * @constructor uiDate
     * @summary 构造函数
     * @param [options] {Object|String} 组件配置参数|要调用的组件方法名
     * @param [param] {Object} 表示要调用的方法的参数
     * @example
     * // 构件组件
     * $('#numberbox').uiDate({dateFmt: 'yyyy-MM-dd'});
     * // 调用组件方法enable
     * $('#numberbox').uiDate("enable");
     */
    $.fn.uiDate = function (options, param) {
        if (this.length > 0 && typeof options == 'string') {
            return $.fn.uiDate.methods[options](this.first(), param);
        }
        return this.each(function(){
            var me = $(this);
            var cache = me.data(_cacheName);

            options = options || {};
            if (cache) {
                $.extend(cache.options, options);
            } else {
                me.data(_cacheName, {
                    options: $.extend({}, $.fn.uiDate.defaults, me.parseUIConfig(), options)
                });
            }
            _init(me);
        });
    };
    /**
     * 方法
     * @lends uiDate.prototype
     */
    $.fn.uiDate.methods = {
        /**
         * @summary 启用组件
         * @name uiDate#enable
         * @function
         * @returns {jQuery} 方法调用者
         * @example
         * $('#input').uiDate("enable")
         */
        enable: function (target) {
            _enable(target);
            return target;
        },
        /**
         * @summary 禁用组件。
         * @name uiDate#disable
         * @function
         * @returns {jQuery} 方法调用者
         * @example
         * $('#input').uiDate("disable")
         */
        disable: function (target) {
            _disable(target);
            return target;
        },
        setReadonly:function(target,readonly){
            _setReadonly(target,readonly);
            return target;
        }
    };
    /**
     * 默认配置
     * @lends uiDate.prototype
     */
    $.fn.uiDate.defaults =
    {
        /**
         * @type Boolean
         * @default false
         * @summary 是否必填
         */
        required: false,
        /**
         * @type Number
         * @default 150
         * @summary 控件宽度
         */
        width: 150,
        skin: 'default',
        /**
         * 设置初始化时显示的日期值，若不设置则为当前日期，可结合参数alwaysUseStartDate使用
         * @name uiDate#startDate
         * @type String
         * @default ''
         * @summary 默认开始日期
         */
        startDate: '',
        /**
         * 若为true，则控件初始化时，无论输入框的值是否为空都将使用开始日期作为默认值
         * @type Boolean
         * @default false
         * @summary 是否始终使用默认开始日期
         */
        alwaysUseStartDate: false,
        /**
         * @type Boolean
         * @default false
         * @summary 双日历
         */
        doubleCalendar: false,
        /**
         * 若不设置，最小日期为1900-01-01 00:00:00<br/>
         * 其它特性同maxDate
         * @type String
         * @default ''
         * @summary 限制最小日期
         */
        minDate: '',
        /**
         * 若不设置，最大日期为2099-12-31 23:59:59<br/>
         * 可以通过系统给出的动态变量,如%y(当前年),%M(当前月)等来限度日期范围,你还可以通过{}进行表达式运算,如:{%d+1}:表示明天<br/>
         * 动态变量表:<br/>
         * <TABLE cellSpacing="1" width="100%" class="params">
         * <TR>
         * <TH width="12%">格式</TH>
         * <TH width="88%">说明</TH></TR>
         * <TR><TD align=center>%y</TD><TD>当前年</TD></TR>
         * <TR><TD align=center>%M</TD><TD>当前月</TD></TR>
         * <TR><TD align=center>%d</TD><TD>当前日</TD></TR>
         * <TR><TD align=center>%ld</TD><TD>本月最后一天</TD></TR>
         * <TR><TD align=center>%H</TD><TD>当前时</TD></TR>
         * <TR><TD align=center>%m</TD><TD>当前分</TD></TR>
         * <TR><TD align=center>%s</TD><TD>当前秒</TD></TR>
         * <TR><TD align=center>{}</TD><TD>运算表达式,如:{%d+1}:表示明天 </TD></TR>
         * <TR><TD align=center>#F{}</TD><TD>{}之间是函数可写自定义JS代码</TD></TR>
         * </TABLE>
         * @type String
         * @default ''
         * @summary 限制最大日期
         */
        maxDate: '',
        /**
         * 设置为true时，无效天和无效日期变成有效天和有效日期
         * 使用无效天和无效日期可以很方便的禁用不可用的日期,但是在只需要启用少部分日期的情况下,有效天和有效日期的功能就非常适合了<br/>
         * @type Boolean
         * @default false
         * @summary 有效天与有效日期反转
         */
        opposite: false,
        /**
         * 可以使用此功能禁用周日至周六所对应的日期(0至6 分别代表 周日至周六)
         * @type Array<Number>
         * @default []
         * @summary 设置不可用的天
         */
        disabledDays: [],
        /**
         * 可以使用此功能禁用,所指定的一个或多个日期,只要你熟悉正则表达式,你可以尽情发挥<br/>
         * ['2008-02-01','2008-02-29'] 表示禁用 2008-02-01 和 2008-02-29<br/>
         * ['2008-..-01','2008-02-29'] 表示禁用 2008-所有月份-01 和 2008-02-29<br/>
         * ['200[0-8]]-02-01','2008-02-29'] 表示禁用 [2000至2008]-02-01 和 2008-02-29<br/>
         * ['^2006'] 表示禁用 2006年的所有日期<br/>
         * 此外,您还可以使用 %y %M %d %H %m %s 等变量, 用法同动态日期限制 注意:%ld不能使用<br/>
         * ['....-..-01','%y-%M-%d'] 表示禁用 所有年份和所有月份的第一天和今天<br/>
         * ['%y-%M-{%d-1}','%y-%M-{%d+1}'] 表示禁用 昨天和明天<br/>
         * 当然,除了可以限制日期以外,您还可以限制时间<br/>
         * ['....-..-.. 10\:00\:00'] 表示禁用 每天10点 (注意 : 需要 使用 \: )
         * @type Array<String>
         * @default []
         * @summary 设置不可用的日期
         */
        disabledDates: [],
        /**
         * @type Array<Number>
         * @default []
         * @summary 设置特殊的天
         */
        specialDays: [],
        /**
         * @type Array<String>
         * @default []
         * @summary 设置特殊的日期
         */
        specialDates: [],
        /**
         * 纠错处理可设置为3种模式:提示(默认) 自动纠错 标记,当日期框中的值不符合格式时,系统会尝试自动修复,
         * 如果修复失败会根据您设置的纠错处理模式进行处理,错误判断功能非常智能它可以保证用户输入的值是一个合法的值
         * 使用默认容错模式 提示模式 errDealMode = 0 在输入错误日期时,会先提示
         * 自动纠错模式 errDealMode = 1 在输入错误日期时,自动恢复前一次正确的值
         * 标记模式 errDealMode = 2 在输入错误日期时,不做提示和更改,只是做一个标记,但此时日期框不会马上隐藏
         * @type Number
         * @default 1
         * @summary 自动纠错功能
         */
        errDealMode: 1,
        /**
         <P>yMdHmswW分别代表年月日时分秒星期周,你可以任意组合这些元素来自定义你个性化的日期格式. </P><BR>日期格式表
         <TABLE cellSpacing="1" width="100%" class="params">
         <TBODY>
         <TR>
         <TH width="12%">格式</TH>
         <TH width="88%">说明</TH></TR>
         <TR>
         <TD align=center>y</TD>
         <TD>将年份表示为最多两位数字。如果年份多于两位数，则结果中仅显示两位低位数。</TD></TR>
         <TR>
         <TD align=center>yy </TD>
         <TD>同上，如果小于两位数，前面补零。</TD></TR>
         <TR>
         <TD align=center>yyy</TD>
         <TD>将年份表示为三位数字。如果少于三位数，前面补零。</TD></TR>
         <TR>
         <TD align=center>yyyy</TD>
         <TD>将年份表示为四位数字。如果少于四位数，前面补零。</TD></TR>
         <TR>
         <TD align=center>M</TD>
         <TD>将月份表示为从 1 至 12 的数字</TD></TR>
         <TR>
         <TD align=center>MM</TD>
         <TD>同上，如果小于两位数，前面补零。</TD></TR>
         <TR>
         <TD align=center>MMM</TD>
         <TD>返回月份的缩写 一月 至 十二月 (英文状态下 Jan to Dec) 。</TD></TR>
         <TR>
         <TD align=center>MMMM</TD>
         <TD>返回月份的全称 一月 至 十二月 (英文状态下 January to December) 。</TD></TR>
         <TR>
         <TD align=center>d</TD>
         <TD>将月中日期表示为从 1 至 31 的数字。</TD></TR>
         <TR>
         <TD align=center>dd</TD>
         <TD>同上，如果小于两位数，前面补零。</TD></TR>
         <TR>
         <TD align=center>H </TD>
         <TD>将小时表示为从 0 至 23 的数字。</TD></TR>
         <TR>
         <TD align=center>HH</TD>
         <TD>同上，如果小于两位数，前面补零。</TD></TR>
         <TR>
         <TD align=center>m</TD>
         <TD>将分钟表示为从 0 至 59 的数字。</TD></TR>
         <TR>
         <TD align=center>mm</TD>
         <TD>同上，如果小于两位数，前面补零。</TD></TR>
         <TR>
         <TD align=center>s</TD>
         <TD>将秒表示为从 0 至 59 的数字。</TD></TR>
         <TR>
         <TD align=center>ss</TD>
         <TD>同上，如果小于两位数，前面补零。</TD></TR>
         <TR>
         <TD align=center>w</TD>
         <TD>返回星期对应的数字 0 (星期天) - 6 (星期六) 。</TD></TR>
         <TR>
         <TD align=center>D</TD>
         <TD>返回星期的缩写 一 至 六 (英文状态下 Sun to Sat) 。</TD></TR>
         <TR>
         <TD align=center>DD</TD>
         <TD>返回星期的全称 星期一 至 星期六 (英文状态下 Sunday to Saturday) 。</TD></TR>
         <TR>
         <TD align=center>W</TD>
         <TD>返回周对应的数字 (1 - 53) 。</TD></TR>
         <TR>
         <TD align=center>WW</TD>
         <TD>同上，如果小于两位数，前面补零 (01 - 53) 。</TD></TR></TBODY></TABLE><BR>示例<BR>
         <TABLE cellSpacing=1 width="100%" class='params'>
         <TBODY>
         <TR>
         <TH width=191>格式字符串</TH>
         <TH width=460>值</TH></TR>
         <TR>
         <TD>yyyy-MM-dd HH:mm:ss</TD>
         <TD>2008-03-12 19:20:00</TD></TR>
         <TR>
         <TD>yy年M月</TD>
         <TD>08年3月</TD></TR>
         <TR>
         <TD>yyyyMMdd</TD>
         <TD>20080312</TD></TR>
         <TR>
         <TD>今天是:yyyy年M年d HH时mm分 </TD>
         <TD>今天是:2008年3月12日 19时20分</TD></TR>
         <TR>
         <TD>H:m:s</TD>
         <TD>19:20:0</TD></TR>
         <TR>
         <TD>y年</TD>
         <TD>8年</TD></TR>
         <TR>
         <TD>MMMM d, yyyy</TD>
         <TD>三月 12, 2008</TD></TR></TBODY></TABLE>
         * @type String
         * @default 'yyyy-MM-dd'
         * @summary 日期格式
         */
        dateFmt: 'yyyy-MM-dd',
        /**
         * @default false
         * @type Boolean
         * @summary 是否禁用组件
         * @example
         * $('#input').uiDate({disabled:true});
         */
        disabled: false,
        /**
         * 如果日期格式里不包含 d(天) 这个元素时,快速选择将一直显示
         * @default true
         * @type Boolean
         * @summary 是否启用快速选择功能
         */
        qsEnabled: true,
        /**
         * 可以传入5个快速选择日期
         * 日期格式必须与 realDateFmt realTimeFmt 相匹配
         * 除了使用静态的日期值以外,还可以使用动态参数(如:%y,%M分别表示当前年和月)
         * @default []
         * @type Array<String>
         * @summary 快速选择数据
         */
        quickSel: [],
        /**
         * @default false
         * @type Boolean
         * @example
         * $('#input').uiDate({readonly:true});
         * @summary 是否只读
         */
        readonly: false,
        /**
         * 可以通过配置此属性决定是否限制周,并且在返回日期的时候还可以通过自带的自定义事件和API函数返回选择的周
         * @default false
         * @type Boolean
         * @summary 是否显示周
         * @example
         * $('#input').uiDate({isShowWeek:true,onpicked:function(){$dp.$('d122_1').value=$dp.cal.getP('W','W');$dp.$('d122_2').value=$dp.cal.getP('W','WW');}});
         */
        isShowWeek: false,
        /**
         * @default true
         * @type Boolean
         * @summary 是否高亮周末
         */
        highLineWeekDay: true,
        /**
         * @default true
         * @type Boolean
         * @summary 是否显示清空按钮
         */
        isShowClear: true,
        /**
         * @default true
         * @type Boolean
         * @summary 是否显示今天按钮
         */
        isShowToday: true,
        /**
         * 例如{left:100,top:100}
         * @default {}
         * @type Object
         * @summary 自定义换件的显示位置
         */
        position: {},
        /**
         * 各个国家的习惯不同,有些喜欢以星期日作为第一天,有些以星期一作为第一天.
         * 相关属性:firstDayOfWeek: 可设置 0 - 6 的任意一个数字,0:星期日 1:星期一 以此类推
         * @default 1
         * @type Number
         * @summary 自定义星期的第一天
         */
        firstDayOfWeek: 1,
        /**
         * 在输入框失去焦点时触发的方法。
         * @event
         * @name uiDate#onpicking
         * @param dp {Object} 控件API
         * @default emptyFn
         * @example
         * $('#input').uiDate({onpicking:function(dp){
         * if(!confirm('日期框原来的值为: '+dp.cal.getDateStr()+', 要用新选择的值:' + dp.cal.getNewDateStr() + '覆盖吗?'))
         * return true;
         * }});
         * @summary 在输入框失去焦点时触发
         */
        onpicking: function (dp) {},
        /**
         * @summary 在输入框失去焦点时触发的方法。
         * @event
         * @name uiDate#onpicked
         * @param dp {Object} 控件API
         * @default emptyFn
         * @example
         * 选择第一个日期的时候,第二个日期选择框自动弹出
         * 注意:下面第一个控件代码的写法
         * <input id="d5221" class="Wdate" type="text" onFocus="var d5222=$dp.$('d5222');WdatePicker({onpicked:function(){d5222.focus();},maxDate:'#F{$dp.$D(\'d5222\')}'})"/>
         * 至
         * <input id="d5222" class="Wdate" type="text" onFocus="WdatePicker({minDate:'#F{$dp.$D(\'d5221\')}'})"/>
         * 注意:$dp.$是一个内置函数,相当于document.getElementById
         */
        onpicked: function (dp) {},
        /**
         * 当函数返回true时,系统的清空事件将被取消
         * @summary 在输入框的值被清空时触发的方法。
         * @event
         * @name uiDate#onclearing
         * @default emptyFn
         */
        onclearing: function () {
        },
        /**
         * @summary 在输入框的值被清空后触发的方法。
         * @param dp {Object} 控件API
         * @event
         * @name uiDate#oncleared
         * @default emptyFn
         */
        oncleared: function (dp) {},
        /**
         * 在方法内可使用$dp.cal.date和$dp.cal.newdate获得更改前后的日期对象<br>
         * 类似的事件有Mchanging、dchanging、Hchanging、mchanging和schanging
         * @event
         * @summary 年份更改时触发的事件
         * @name uiDate#ychanging
         * @default emptyFn
         */
        ychanging: function () {},
        /**
         * 在方法内可使用$dp.cal.date和$dp.cal.newdate获得更改前后的日期对象<br>
         * 类似的事件有Mchanged、dchanged、Hchanged、mchanged和schanged
         * @event
         * @summary 年份更改后触发的事件
         * @name uiDate#ychanged
         * @default emptyFn
         */
        ychanged: function () {},
        Mchanging: function () {},
        Mchanged: function () {},
        dchanging: function () {},
        dchanged: function () {},
        Hchanging: function () {},
        Hchanged: function () {},
        mchanging: function () {},
        mchanged: function () {},
        schanging: function () {},
        schanged: function () {}
    };
//////--------------------------------内部方法------------------------------
    /**
     * 创建按钮
     * @param target 目标对象
     */
    var _init = function (target) {
        var options = $.data(target[0], _cacheName).options;
        target.setElemID().addClass('ui_date');
        var targetID = target.getElemID();
        if (typeof options.disabled !== "boolean") {
            options.disabled = target.attr("disabled");
        }
        var span = $($.uiTemplate.datepicker.pickerHtml).setIDByParentID(targetID, $.uiTemplate.datepicker.pickerSpan);
        target.wrap(span);
        var icon = $($.uiTemplate.datepicker.iconHtml).setIDByParentID(targetID, $.uiTemplate.datepicker.icon);
        target.after(icon);
        _setReadonly(target,options.readonly);
        if(_IEunder7) {
            target.outerWidth(options.width - icon.outerWidth());
        }else{
            target.outerWidth(options.width - icon.outerWidth()+2);
        }

        return target;
    };
    var _disable = function (target) {
        var icon = $.getByParentID(target.getElemID(), $.uiTemplate.datepicker.icon);
        target.attr("disabled", true)
            .addClass("ui-disabled");
        target.unbind('.uiDate');
        icon.unbind('.uiDate');
    };
    var _enable = function (target) {
        var options = $.data(target[0], _cacheName).options;
        target.attr("disabled", false)
            .removeClass("ui-disabled");
        var icon = $.getByParentID(target.getElemID(), $.uiTemplate.datepicker.icon);
        var span = $.getByParentID(target.getElemID(), $.uiTemplate.datepicker.pickerSpan);
        icon.unbind('.uiDate').bind('click.uiDate', function () {
            target.focus();
        });
        target.unbind('.uiDate').bind('focus.uiDate',function () {
            span.addClass('ui_date-focus');
            WdatePicker(options);
        }).bind('blur.uiDate', function () {
                span.removeClass('ui_date-focus');
            });
        if (options.required) {
            target.uiValidate({
                required: true,
                tipOffset: [20, 0],
                afterValidate: function (validate) {
                    if (!validate) {
                        span.addClass('ui_date-invalid');
                    } else {
                        span.removeClass('ui_date-invalid');
                    }
                }
            });
            target.css('border','0');
        }
    };
    var _setReadonly = function (target, readonly) {
        var options = $.data(target[0], _cacheName).options;
        var icon = $.getByParentID(target.getElemID(), $.uiTemplate.datepicker.icon);
        var span = $.getByParentID(target.getElemID(), $.uiTemplate.datepicker.pickerSpan);
        var input = span.find('.ui_date');
        if (readonly) {
            span.addClass('ui_validate_disabled');
            icon.hide();
            input.width(input.width() + 20);
            target.attr('readonly',true);
            target.unbind('.uiDate');
            icon.unbind('.uiDate');
            var starId=target.attr('id')+'-star';
            $('#'+starId).remove();
        } else {
            span.removeClass('ui_validate_disabled');
            icon.show();
            input.width(input.width() - 20);
            if (options.disabled) {
                _disable(target);
            } else {
                _enable(target);
            }
        }
    }
})(jQuery);